<!DOCTYPE html><html lang="zh-Hans"><head><meta name="generator" content="Hexo 3.8.0"><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0" name="viewport"><meta content="yes" name="apple-mobile-web-app-capable"><meta content="black-translucent" name="apple-mobile-web-app-status-bar-style"><meta content="telephone=no" name="format-detection"><meta name="description" content="漫漫IT路，持一颗恒心，带一份执着！"><title>菜鸟IT路 | dev-heaven</title><link rel="stylesheet" type="text/css" href="/css/style.css?v=0.0.0"><link rel="stylesheet" type="text/css" href="//lib.baomitu.com/normalize/8.0.1/normalize.min.css"><link rel="stylesheet" type="text/css" href="//lib.baomitu.com/pure/1.0.0/pure-min.css"><link rel="stylesheet" type="text/css" href="//lib.baomitu.com/pure/1.0.0/grids-responsive-min.css"><link rel="stylesheet" href="//lib.baomitu.com/font-awesome/4.7.0/css/font-awesome.min.css"><script type="text/javascript" src="//lib.baomitu.com/jquery/3.4.0/jquery.min.js"></script><link rel="icon" mask sizes="any" href="/favicon.ico"><link rel="Shortcut Icon" type="image/x-icon" href="/favicon.ico"><link rel="apple-touch-icon" href="/apple-touch-icon.png"><link rel="apple-touch-icon-precomposed" href="/apple-touch-icon.png"></head><body><div class="body_container"><div id="header"><div class="site-name"><h1 class="hidden">菜鸟IT路</h1><a id="logo" href="/.">菜鸟IT路</a><p class="description">dev-heaven</p></div><div id="nav-menu"><a class="current" href="/."><i class="fa fa-home">Inicio</i></a><a href="/archives/"><i class="fa fa-archive"> Archivo</i></a><a href="/about/"><i class="fa fa-user"> Acerca de</i></a><a href="/atom.xml"><i class="fa fa-rss"> RSS</i></a></div></div><div class="pure-g" id="layout"><div class="pure-u-1 pure-u-md-3-4"><div class="content_container"><div class="post"><h1 class="post-title"><a href="/posts/21375.html">Docker 操作简记</a></h1><div class="post-meta">2017-04-17</div><div class="post-content"><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> centos:<span class="number">7</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> yun install -y git</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> yum install -y nginx</span></span><br></pre></td></tr></table></figure><figure class="highlight pf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 拉取镜像</span></span><br><span class="line">docker pull <span class="variable">&lt;image-name&gt;</span></span><br><span class="line"><span class="comment"># 本地提交镜像</span></span><br><span class="line">docker commit <span class="variable">&lt;image-id&gt;</span> <span class="variable">&lt;namespace&gt;</span>/<span class="variable">&lt;image-name&gt;</span></span><br><span class="line">docker commit f30 jarvan4dev/centos7</span><br><span class="line"><span class="comment"># 启动容器</span></span><br><span class="line">docker start <span class="variable">&lt;container-id&gt;</span></span><br><span class="line"><span class="comment"># 停止所有容器</span></span><br><span class="line">docker ps -a | awk '&#123;print <span class="variable">$1</span>&#125;' | xargs docker rm</span><br><span class="line"><span class="comment"># 查看所有容器</span></span><br><span class="line">docker ps -a</span><br><span class="line"><span class="comment"># 进入容器内部</span></span><br><span class="line">docker attach <span class="variable">&lt;container-id&gt;</span></span><br><span class="line"><span class="comment"># 运行某个镜像</span></span><br><span class="line">docker run -it -v /Users/jarvan4dev/Documents/docker:/ -p <span class="number">20000</span>:<span class="number">80</span> centos /bin/bash</span><br><span class="line"><span class="comment"># 提交镜像</span></span><br><span class="line">docker login --username=<span class="variable">&lt;阿里云用户名&gt;</span> <span class="variable">&lt;阿里云仓库地址&gt;</span></span><br><span class="line">docker <span class="keyword">tag</span> <span class="variable">&lt;image-id&gt;</span> <span class="variable">&lt;阿里云仓库地址&gt;</span>:<span class="variable">&lt;自定义版本&gt;</span></span><br><span class="line">docker push <span class="variable">&lt;阿里云仓库地址&gt;</span>:<span class="variable">&lt;自定义版本&gt;</span></span><br></pre></td></tr></table></figure><p>reference：<br><a href="http://welcomeweb.blog.51cto.com/10487763/1735251" target="_blank" rel="noopener">http://welcomeweb.blog.51cto.com/10487763/1735251</a></p></div><p class="readmore"><a href="/posts/21375.html">Leer más</a></p></div><div class="post"><h1 class="post-title"><a href="/posts/25797.html">Spring容器生命周期</a></h1><div class="post-meta">2017-03-23</div><div class="post-content"><p>如何在Spring应用启动后立即加载数据到缓存?</p><p>如何在Spring启动后执行某个任务？当然可以用quartz，但是没有必要</p><p>1、@PreConstruct</p><p>2、class MissionStarter implement InitializingBean</p></div><p class="readmore"><a href="/posts/25797.html">Leer más</a></p></div><div class="post"><h1 class="post-title"><a href="/posts/37887.html">SQL中的连接</a></h1><div class="post-meta">2017-03-22</div><p class="readmore"><a href="/posts/37887.html">Leer más</a></p></div><div class="post"><h1 class="post-title"><a href="/posts/34407.html">springMVC中的x-www-form-urlencoded和form-data</a></h1><div class="post-meta">2017-03-19</div><div class="post-content"><blockquote><p>写好的接口经常会拿chrome中的插件postman进行测试，在postman中有两个选项，一个是 <code>form-data</code>，另一个是 <code>x-www-form-urlencoded</code>，有什么不同呢？</p></blockquote><p><img src="https://static.dev-heaven.com/images/8B3100BD-3A39-4001-B9CF-C1D87FB290F3.png" alt></p></div><p class="readmore"><a href="/posts/34407.html">Leer más</a></p></div><div class="post"><h1 class="post-title"><a href="/posts/10499.html">ScheduledExecutorService</a></h1><div class="post-meta">2017-03-17</div><div class="post-content"><blockquote><p>突然想起以前写的代码，处理的任务就是去平台查询订单状态，根据订单状态做后续处理。处理过程如下：</p></blockquote><figure class="highlight axapta"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">Order <span class="keyword">order</span> = orderMapper.getOrder(orderId); <span class="comment">// 从数据库查出订单</span></span><br><span class="line"><span class="keyword">int</span> status = <span class="keyword">order</span>.getStatus();</span><br><span class="line"><span class="keyword">int</span> queryCount = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">while</span>(<span class="keyword">true</span>) &#123;<span class="comment">// 初始化状态</span></span><br><span class="line">   status = queryStatusFromPlatform(orderId); <span class="comment">// 从平台查询订单状态</span></span><br><span class="line">   <span class="keyword">order</span>.setStatus(status);</span><br><span class="line">   <span class="keyword">if</span>(status == <span class="number">0</span>) &#123;</span><br><span class="line">	sleep(<span class="number">500</span>);<span class="comment">// 线程停500ms</span></span><br><span class="line">   &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">	notify(<span class="keyword">order</span>);</span><br><span class="line">	<span class="keyword">break</span>;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">if</span> (queryCount &gt;= <span class="number">5</span>) &#123;</span><br><span class="line">	<span class="keyword">break</span>;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 通知第三方</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> notify(Order <span class="keyword">order</span>) &#123;</span><br><span class="line">   <span class="keyword">while</span>(<span class="keyword">true</span>) &#123;</span><br><span class="line">	<span class="comment">// 这里也是循环，发起通知，正确收到返回则停止，否则重试</span></span><br><span class="line">	sleep(<span class="number">500</span>);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>其实问题没什么大问题，但是当系统中任务比较多的时候，如果线程挂起，线程无法释放，会导致很多资源占用致使系统资源不足，可能会宕机 :smile</p><p>下面我们来用ScheduledExecutorService进行下改造！除了性能之外，代码会变得更优雅！做个有洁癖的程序员。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure></div><p class="readmore"><a href="/posts/10499.html">Leer más</a></p></div><div class="post"><h1 class="post-title"><a href="/posts/50849.html">乐观锁在MySQL中的应用</a></h1><div class="post-meta">2017-03-16</div><div class="post-content"><p>失败重试机制：<a href="http://blog.csdn.net/nihao_8/article/details/39525807" target="_blank" rel="noopener">http://blog.csdn.net/nihao_8/article/details/39525807</a></p><p><a href="http://blog.csdn.net/zhanghongzheng3213/article/details/50819539" target="_blank" rel="noopener">http://blog.csdn.net/zhanghongzheng3213/article/details/50819539</a></p></div><p class="readmore"><a href="/posts/50849.html">Leer más</a></p></div><div class="post"><h1 class="post-title"><a href="/posts/56547.html">乐观锁与悲观锁</a></h1><div class="post-meta">2017-03-16</div><div class="post-content"><p><a href="http://www.tuicool.com/articles/yiyy6bI" target="_blank" rel="noopener">http://www.tuicool.com/articles/yiyy6bI</a></p><p><a href="http://chenzhou123520.iteye.com/blog/1863407" target="_blank" rel="noopener">http://chenzhou123520.iteye.com/blog/1863407</a></p></div><p class="readmore"><a href="/posts/56547.html">Leer más</a></p></div><div class="post"><h1 class="post-title"><a href="/posts/43085.html">spring-data-redis之秒杀</a></h1><div class="post-meta">2017-03-16</div><div class="post-content"><blockquote><p>在现代电商中，秒杀是常用的促销手段，秒杀带来促销的同时，无疑给IT系统带来巨大冲击，今天我们就来模拟下秒杀。</p></blockquote><h4 id="超卖原因"><a href="#超卖原因" class="headerlink" title="超卖原因"></a>超卖原因</h4><p>下面我们说说，抢购流程！</p><p><img src="https://static.dev-heaven.com/images/QQ20170316-201422@2x.png" alt="购买流程图"></p><p>在上面的图中，如果购买的人只有一个是没有问题的，但是如果是两个就有问题，可能会出现“超卖现象”。</p><ol><li>有A，B两个线程操作数据库。</li><li>假设此时库存为1，即只允许一人买。</li><li>A先查到数据库获取库存，A进行购买，支付成功后库存进行减一操作，但此时由于CPU切换，A被挂起。</li><li>B访问数据库，此时A还未更新，B同样进行了购买，B成功进行了减一操作，数据库数量变为0，这个时候A被唤醒，也进行了减一操作，这就导致了库存变为-1，导致超卖。</li></ol><h4 id="如何控制？"><a href="#如何控制？" class="headerlink" title="如何控制？"></a>如何控制？</h4><h5 id="方式一"><a href="#方式一" class="headerlink" title="方式一"></a>方式一</h5><p>加锁！最简单的方式，强制线程同步。同时缺点也很明显，那就是某一个线程操作的时候，其他线程必须等待它执行结束才能获取执行权。synchronized是典型的悲观锁，等待时间非常长，响应慢 。</p><h5 id="方式二"><a href="#方式二" class="headerlink" title="方式二"></a>方式二</h5><p>使用队列，所有的请求全部进入队列，取其中前n个处理，其他的丢弃。但是并发量高的话，并发量会让队列内存瞬间升高，影响服务器性能。</p><h5 id="方式三"><a href="#方式三" class="headerlink" title="方式三"></a>方式三</h5><p>使用乐观锁，乐观锁的一种实现是CAS(Compare And Swap)，其思想是假设数据一般情况下没有冲突，在数据进行提交更新的时候，才会正式对数据的冲突与否进行检测，如果发现冲突了，则让返回用户错误的信息，让用户决定如何去做（在当前的情景下，直接返回秒杀失败即可）。</p><h4 id="乐观锁实践"><a href="#乐观锁实践" class="headerlink" title="乐观锁实践"></a>乐观锁实践</h4><p>乐观锁，可以用redis的watch实现，也可以用MySQL实现，高并发情况下还是选择redis比较靠谱。其MySQL实现，请参看我的另一篇博客《乐观锁在MySQL中的应用》。</p><h5 id="redis为什么能实现乐观锁？"><a href="#redis为什么能实现乐观锁？" class="headerlink" title="redis为什么能实现乐观锁？"></a>redis为什么能实现乐观锁？</h5><p>在Redis的事务中，WATCH命令可用于提供CAS功能。假设我们通过WATCH命令在事务执行之前监控了多个Keys，倘若在WATCH之后有任何Key的值发生了变化，EXEC命令执行的事务都将被放弃，同时返回Null multi-bulk应答以通知调用者事务执行失败。</p><h5 id="具体实践"><a href="#具体实践" class="headerlink" title="具体实践"></a>具体实践</h5><p>当商户在后台添加商品的时候，输入商品数，此时将商品的id作为key（key有规范的哦！），数量作为值，存入redis。</p><blockquote><p>Talk is cheap, show me the code!</p></blockquote><h5 id="spring-redis-xml"><a href="#spring-redis-xml" class="headerlink" title="spring-redis.xml"></a>spring-redis.xml</h5><figure class="highlight dust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="meta">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span></span></span><br><span class="line"><span class="xml"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></span></span><br><span class="line"><span class="xml">       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"</span></span><br><span class="line"><span class="xml">       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"&gt;</span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml">    <span class="comment">&lt;!-- 连接池配置  最大连接数 最大空闲数  最长等待时间 连接是否可用--&gt;</span></span></span><br><span class="line"><span class="xml">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"jedisPoolConfig"</span> <span class="attr">class</span>=<span class="string">"redis.clients.jedis.JedisPoolConfig"</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!--最大连接数--&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"maxTotal"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.maxActive&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!--最大空闲数--&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"maxIdle"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.maxIdle&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!--最大连接数后最长阻塞时间--&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"maxWaitMillis"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.maxWaitMillis&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!--当连接给调用者使用时，是否检测其有效性--&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"testOnBorrow"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.testOnBorrow&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!--归还连接时，是否检测其有效性--&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"testOnReturn"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.testOnReturn&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!--达到最大连接数是否阻塞--&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"blockWhenExhausted"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.blockWhenExhausted&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!--空闲连接的检测周期--&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"timeBetweenEvictionRunsMillis"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.timeBetweenEvictionRunsMillis&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!--当连接给调用者使用时，是否检测空间超时--&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"testWhileIdle"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.testWhileIdle&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"jedisConnectionFactory"</span></span></span></span><br><span class="line"><span class="xml">          class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"</span></span><br><span class="line"><span class="xml">          destroy-method="destroy"&gt;</span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"hostName"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.host&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"port"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.port&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"password"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.password&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"usePool"</span> <span class="attr">value</span>=<span class="string">"$</span></span></span><span class="template-variable">&#123;redis.usePool&#125;</span><span class="xml"><span class="tag"><span class="string">"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"poolConfig"</span> <span class="attr">ref</span>=<span class="string">"jedisPoolConfig"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml">    <span class="comment">&lt;!--RedisTemplate：可操作对象，最终会将对象转化为字节（所以对象需支持序列化和反序列化）--&gt;</span></span></span><br><span class="line"><span class="xml">    <span class="comment">&lt;!--StringRedisTemplate:操作对象是String类型--&gt;</span></span></span><br><span class="line"><span class="xml">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"redisTemplate"</span> <span class="attr">class</span>=<span class="string">"org.springframework.data.redis.core.RedisTemplate"</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!--开启事务支持--&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"enableTransactionSupport"</span> <span class="attr">value</span>=<span class="string">"true"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"connectionFactory"</span> <span class="attr">ref</span>=<span class="string">"jedisConnectionFactory"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="comment">&lt;!-- 序列化方式 建议key/hashKey采用StringRedisSerializer。 --&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"keySerializer"</span>&gt;</span></span></span><br><span class="line"><span class="xml">            <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">"org.springframework.data.redis.serializer.StringRedisSerializer"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"hashKeySerializer"</span>&gt;</span></span></span><br><span class="line"><span class="xml">            <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">"org.springframework.data.redis.serializer.StringRedisSerializer"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"valueSerializer"</span>&gt;</span></span></span><br><span class="line"><span class="xml">            <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">"org.springframework.data.redis.serializer.StringRedisSerializer"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"hashValueSerializer"</span>&gt;</span></span></span><br><span class="line"><span class="xml">            <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">"org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"</span>/&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span></span><br><span class="line"><span class="xml">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span></span><br><span class="line"><span class="xml"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span></span><br></pre></td></tr></table></figure><h5 id="redis-properties"><a href="#redis-properties" class="headerlink" title="redis.properties"></a>redis.properties</h5><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#一个pool可分配多少个jedis实例</span></span><br><span class="line"><span class="attr">redis.maxActive</span>=<span class="number">2048</span></span><br><span class="line"><span class="comment">#一个pool最多可有多少个状态为idle（空闲）的jedis实例</span></span><br><span class="line"><span class="attr">redis.maxIdle</span>=<span class="number">300</span></span><br><span class="line"><span class="comment">#当borrow一个jedis实例时，最大的等待时间，如果超过了等待时间，则直接抛出JedisConnectionException</span></span><br><span class="line"><span class="attr">redis.maxWaitMillis</span>=<span class="number">10000</span></span><br><span class="line"><span class="comment">#在borrow一个jedis实例时，是否提前进行validate操作，如果为true，则得到的jedis实例时可用的</span></span><br><span class="line"><span class="attr">redis.testOnBorrow</span>=<span class="literal">true</span></span><br><span class="line"><span class="comment">#连接耗尽时是否阻塞，false报异常，true阻塞直到超时，默认为true</span></span><br><span class="line"><span class="attr">redis.testOnReturn</span>=<span class="literal">false</span></span><br><span class="line"><span class="attr">redis.blockWhenExhausted</span>=<span class="literal">true</span></span><br><span class="line"><span class="attr">redis.testWhileIdle</span>=<span class="literal">false</span></span><br><span class="line"><span class="attr">redis.timeBetweenEvictionRunsMillis</span>=<span class="number">60000</span></span><br><span class="line"><span class="attr">redis.host</span>=<span class="number">127.0</span>.<span class="number">0.1</span></span><br><span class="line"><span class="attr">redis.port</span>=<span class="number">6379</span></span><br><span class="line"><span class="attr">redis.password</span>=huweitech</span><br><span class="line"><span class="attr">redis.usePool</span>=<span class="literal">true</span></span><br></pre></td></tr></table></figure><h5 id="Java-Code"><a href="#Java-Code" class="headerlink" title="Java Code"></a>Java Code</h5><figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.huweitech.redis.test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.junit.<span class="type">Test</span>;</span><br><span class="line"><span class="keyword">import</span> org.junit.runner.<span class="type">RunWith</span>;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.<span class="type">Autowired</span>;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.<span class="type">RedisTemplate</span>;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.<span class="type">ValueOperations</span>;</span><br><span class="line"><span class="keyword">import</span> org.springframework.test.context.<span class="type">ContextConfiguration</span>;</span><br><span class="line"><span class="keyword">import</span> org.springframework.test.context.junit4.<span class="type">AbstractJUnit4SpringContextTests</span>;</span><br><span class="line"><span class="keyword">import</span> org.springframework.test.context.junit4.<span class="type">SpringJUnit4ClassRunner</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.<span class="type">ExecutorService</span>;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.<span class="type">Executors</span>;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.<span class="type">TimeUnit</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Created by jarvan4dev on 2017/3/11.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@ContextConfiguration</span>(locations = <span class="string">"classpath:spring-context.xml"</span>)</span><br><span class="line"><span class="meta">@RunWith</span>(<span class="type">SpringJUnit4ClassRunner</span>.<span class="keyword">class</span>)</span><br><span class="line">public <span class="class"><span class="keyword">class</span> <span class="title">RedisTest</span> <span class="keyword">extends</span> <span class="title">AbstractJUnit4SpringContextTests</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> static <span class="keyword">final</span> <span class="type">String</span> myWatchKey = <span class="string">"myWatchKey"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> <span class="type">RedisTemplate</span>&lt;<span class="type">String</span>, <span class="type">String</span>&gt; redisTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    public void testWatch() <span class="keyword">throws</span> <span class="type">InterruptedException</span> &#123;</span><br><span class="line">        <span class="type">System</span>.out.println(redisTemplate.getDefaultSerializer());</span><br><span class="line">        <span class="type">ValueOperations</span>&lt;<span class="type">String</span>, <span class="type">String</span>&gt; valueOperations = redisTemplate.opsForValue();</span><br><span class="line">        valueOperations.set(myWatchKey, <span class="string">"10"</span>);</span><br><span class="line">        <span class="type">ExecutorService</span> executor = <span class="type">Executors</span>.newFixedThreadPool(<span class="number">200</span>);</span><br><span class="line">        <span class="keyword">for</span> (int i=<span class="number">0</span>; i&lt; <span class="number">10000</span>; i++) &#123;</span><br><span class="line">            executor.execute(<span class="keyword">new</span> <span class="type">SecKillRunnable</span>(redisTemplate));</span><br><span class="line">        &#125;</span><br><span class="line">        executor.awaitTermination(<span class="number">30</span>, <span class="type">TimeUnit</span>.<span class="type">SECONDS</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight processing"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.huweitech.redis.test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.RedisTemplate;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.ValueOperations;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Created by jarvan4dev on 2017/3/16.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> class SecKillRunnable implements Runnable&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">String</span> myWatchKey = <span class="string">"myWatchKey"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> RedisTemplate&lt;<span class="keyword">String</span>, <span class="keyword">String</span>&gt; redisTemplate;</span><br><span class="line">    <span class="keyword">private</span> ValueOperations&lt;<span class="keyword">String</span>, <span class="keyword">String</span>&gt; valueOperations;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> SecKillRunnable(RedisTemplate&lt;<span class="keyword">String</span>, <span class="keyword">String</span>&gt; redisTemplate) &#123;</span><br><span class="line">        <span class="keyword">this</span>.redisTemplate = redisTemplate;</span><br><span class="line">        <span class="keyword">this</span>.valueOperations = redisTemplate.opsForValue();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> run() &#123;</span><br><span class="line">        System.out.<span class="built_in">println</span>(<span class="string">"线程执行"</span>);</span><br><span class="line">        redisTemplate.watch(myWatchKey);</span><br><span class="line">        Integer count = Integer.parseInt(valueOperations.<span class="built_in">get</span>(myWatchKey));</span><br><span class="line">        System.out.<span class="built_in">println</span>(<span class="string">"当前剩余数量："</span> + count);</span><br><span class="line">        <span class="keyword">if</span> (count &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            System.out.<span class="built_in">println</span>(<span class="string">"进入"</span>);</span><br><span class="line">            redisTemplate.multi();</span><br><span class="line">            valueOperations.increment(myWatchKey, <span class="number">-1</span>);</span><br><span class="line">            List&lt;<span class="keyword">Object</span>&gt; list = redisTemplate.exec();</span><br><span class="line">            <span class="keyword">if</span> (list != <span class="keyword">null</span>) &#123;</span><br><span class="line">                System.out.<span class="built_in">println</span>(<span class="string">"秒杀成功"</span>);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                System.out.<span class="built_in">println</span>(<span class="string">"秒杀失败"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            System.out.<span class="built_in">println</span>(<span class="string">"秒杀结束了"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>关于spring-data-redis的RedisSerializer，请参看下面的第二篇参考链接。</p><h4 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h4><ol><li><a href="http://lib.csdn.net/article/redis/18162" target="_blank" rel="noopener">http://lib.csdn.net/article/redis/18162</a></li><li><a href="http://blog.csdn.net/wangjun5159/article/details/52387782" target="_blank" rel="noopener">http://blog.csdn.net/wangjun5159/article/details/52387782</a></li></ol></div><p class="readmore"><a href="/posts/43085.html">Leer más</a></p></div><div class="post"><h1 class="post-title"><a href="/posts/2937.html">SpringMVC下载文件</a></h1><div class="post-meta">2017-03-12</div><div class="post-content"><blockquote><p>在微信开发中<br>根据微信要求：<br>将文件MP_verify_bLdKbdjQoQFPia5u.txt（点击下载）<br>上传至填写域名或路径指向的web服务器（或虚拟主机）的目录（若填写域名，将文件放置在域名根目录下，<br>例如wx.qq.com/MP_verify_bLdKbdjQoQFPia5u.txt；<br>若填写路径，将文件放置在路径目录下，例如wx.qq.com/mp/MP_verify_bLdKbdjQoQFPia5u.txt），并确保可以访问。</p><p>本来放在Nginx中直接解决了，但是我是本地服务器，当然也可以直接放在工程目录webapp目录下，当时大脑短路，自己弄了个下载服务，后来弄了没什么用，还是留作记录吧，说不定以后用得上。</p></blockquote><p>直接上代码</p><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">@RequestMapping(value = <span class="string">"/MP_verify_bLdKbdjQoQFPia5u.txt"</span>, method = RequestMethod.GET)</span><br><span class="line">   <span class="keyword">public</span> ResponseEntity&lt;<span class="keyword">byte</span>[]&gt; downloadMpFile() <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">       <span class="keyword">File</span> <span class="keyword">file</span> = ResourceUtils.getFile(<span class="string">"classpath:MP_verify_bLdKbdjQoQFPiM5u.txt"</span>);</span><br><span class="line">       HttpHeaders headers = <span class="keyword">new</span> HttpHeaders();</span><br><span class="line">       headers.setContentDispositionFormData(<span class="string">"attachment"</span>, <span class="keyword">new</span> String(<span class="string">"MP_verify_bLdKbdjQoQFPiM5u.txt"</span>.getBytes(<span class="string">"gb2312"</span>), <span class="string">"iso8859-1"</span>));</span><br><span class="line">       <span class="keyword">return</span> <span class="keyword">new</span> ResponseEntity&lt;<span class="keyword">byte</span>[]&gt;(FileUtils.readFileToByteArray(<span class="keyword">file</span>), headers, HttpStatus.OK);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></div><p class="readmore"><a href="/posts/2937.html">Leer más</a></p></div><div class="post"><h1 class="post-title"><a href="/posts/62687.html">Ngrok---内网穿透程序</a></h1><div class="post-meta">2017-03-09</div><div class="post-content"><blockquote><p>在微信开发中，需要将开发者服务器和微信服务器连接起来，但是如果每次修改了代码就要发布到公网，然后再调试，这无疑会大大降低开发速度。所以需要使用Ngrok将本地程序代理到公网，本来一直在使用 <a href="https://www.ngrok.cc/" target="_blank" rel="noopener">sunny-ngrok</a>，一块钱1G流量，而且微信因为是测试开发者账号，所以没有要求域名备案，但是今天申请的服务号下来了，需要备案域名，所以sunny-ngrok就没法使用了。所以还是自己搭建Ngrok服务器咯。</p></blockquote><h4 id="我的配置"><a href="#我的配置" class="headerlink" title="我的配置"></a>我的配置</h4><p>说说我的服务器，阿里云ECS，CentOS.64位。</p><h4 id="Go"><a href="#Go" class="headerlink" title="Go"></a>Go</h4><h5 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h5><p><a href="https://golang.org/doc/install?download=go1.8.linux-amd64.tar.gz" target="_blank" rel="noopener">Go下载地址</a></p><h5 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h5><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">tar -C /usr/local -xzf go1.<span class="number">8</span>.linux-amd64.tar.gz</span><br><span class="line"><span class="comment"># 将以下内容写到 ~/.bash_profile中</span></span><br><span class="line">export PATH=<span class="variable">$PATH</span><span class="symbol">:/usr/local/go/bin</span></span><br><span class="line"><span class="comment"># 别忘了让 .bash_profile生效</span></span><br><span class="line">source ~<span class="regexp">/.bash_profile</span></span><br></pre></td></tr></table></figure><h5 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h5><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[root@iZ94pjjvvshZ src]# <span class="keyword">go</span> <span class="keyword">version</span></span><br><span class="line">输出：<span class="keyword">go</span> <span class="keyword">version</span> go1.<span class="number">8</span> linux/amd64</span><br></pre></td></tr></table></figure><p><em>以上内容在Go的下载页面都有说明。</em></p><h4 id="Ngrok"><a href="#Ngrok" class="headerlink" title="Ngrok"></a>Ngrok</h4><h5 id="下载-1"><a href="#下载-1" class="headerlink" title="下载"></a>下载</h5><figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="keyword">clone</span> <span class="title">https</span>://github.com/inconshreveable/ngrok.git</span><br></pre></td></tr></table></figure><h5 id="生成自签名证书并替换默认证书"><a href="#生成自签名证书并替换默认证书" class="headerlink" title="生成自签名证书并替换默认证书"></a>生成自签名证书并替换默认证书</h5><p>ngrok需要一个域名作为base域名，ngrok会为客户端分配base域名的子域名。例如：ngrok的base域名为tunnel.mydomain.com，客户端即可被分配子域名test.tunnel.mydomain.com。使用ngrok官方服务时，base域名是ngrok.com，并且使用默认的SSL证书。现在自建ngrok服务器，所以需要重新为自己的base域名生成证书。</p><p>我的base domain是<code>dev-heaven.com</code>，打算分配一个子域名wechat.dev-heaven.com给客户端。</p><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">cd ngrok</span><br><span class="line"># 为base域名tunnel.mydomain.com生成证书</span><br><span class="line">openssl genrsa -out rootCA.<span class="type">key</span> <span class="number">2048</span></span><br><span class="line">openssl req -x509 -new -nodes -<span class="type">key</span> rootCA.<span class="type">key</span> -subj <span class="string">"/CN=tunnel.mydomain.com"</span> -days <span class="number">5000</span> -out rootCA.pem</span><br><span class="line">openssl genrsa -out device.<span class="type">key</span> <span class="number">2048</span></span><br><span class="line">openssl req -new -<span class="type">key</span> device.<span class="type">key</span> -subj <span class="string">"/CN=tunnel.mydomain.com"</span> -out device.csr</span><br><span class="line">openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.<span class="type">key</span> -CAcreateserial -out device.crt -days <span class="number">5000</span></span><br></pre></td></tr></table></figure><p>执行完上述命令，正常情况下，该目录会多出device.crt、device.csr、device.key、rootCA.key、rootCA.pem、rootCA.srl六个文件，用它们来替换默认的证书文件即可。默认的证书文件在“./assets/client/tls”和“./assets/server/tls/”目录中</p><figure class="highlight avrasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># 替换默认的证书文件</span></span><br><span class="line"><span class="keyword">cp</span> rootCA.pem assets/client/tls/ngrokroot.crt</span><br><span class="line"><span class="keyword">cp</span> device.crt assets/server/tls/snakeoil.crt </span><br><span class="line"><span class="keyword">cp</span> device.key assets/server/tls/snakeoil.key</span><br></pre></td></tr></table></figure><h5 id="编译生成服务器端"><a href="#编译生成服务器端" class="headerlink" title="编译生成服务器端"></a>编译生成服务器端</h5><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">make</span> release-server release-client</span><br><span class="line">输出：GOOS=<span class="string">""</span> GOARCH=<span class="string">""</span> <span class="keyword">go</span> <span class="built_in">get</span> github.<span class="keyword">com</span>/jteeuwen/<span class="keyword">go</span>-bindata/<span class="keyword">go</span>-bindata</span><br><span class="line">bin/<span class="keyword">go</span>-bindata -nomemcopy -pkg=assets -<span class="keyword">tags</span>=release \</span><br><span class="line">	-<span class="keyword">debug</span>=false \</span><br><span class="line">	-<span class="keyword">o</span>=src/ngrok/client/assets/assets_release.<span class="keyword">go</span> \</span><br><span class="line">	assets/client/...</span><br><span class="line">bin/<span class="keyword">go</span>-bindata -nomemcopy -pkg=assets -<span class="keyword">tags</span>=release \</span><br><span class="line">	-<span class="keyword">debug</span>=false \</span><br><span class="line">	-<span class="keyword">o</span>=src/ngrok/server/assets/assets_release.<span class="keyword">go</span> \</span><br><span class="line">	assets/server/...</span><br><span class="line"><span class="keyword">go</span> <span class="built_in">get</span> -<span class="keyword">tags</span> <span class="string">'release'</span> -d -v ngrok/...</span><br><span class="line">github.<span class="keyword">com</span>/inconshreveable/mousetrap (download)</span><br><span class="line">github.<span class="keyword">com</span>/rcrowley/<span class="keyword">go</span>-metrics (download)</span><br><span class="line">Fetching http<span class="variable">s:</span>//gopkg.in/inconshreveable/<span class="keyword">go</span>-<span class="keyword">update</span>.v0?<span class="keyword">go</span>-<span class="built_in">get</span>=<span class="number">1</span></span><br><span class="line">Parsing meta <span class="keyword">tags</span> from http<span class="variable">s:</span>//gopkg.in/inconshreveable/<span class="keyword">go</span>-<span class="keyword">update</span>.v0?<span class="keyword">go</span>-<span class="built_in">get</span>=<span class="number">1</span> (status code <span class="number">200</span>)</span><br><span class="line"><span class="built_in">get</span> <span class="string">"gopkg.in/inconshreveable/go-update.v0"</span>: found meta <span class="keyword">tag</span> main.metaImport&#123;Prefix:<span class="string">"gopkg.in/inconshreveable/go-update.v0"</span>, VCS:<span class="string">"git"</span>, RepoRoo<span class="variable">t:</span><span class="string">"https://gopkg.in/inconshreveable/go-update.v0"</span>&#125; at http<span class="variable">s:</span>//gopkg.in/inconshreveable/<span class="keyword">go</span>-<span class="keyword">update</span>.v0?<span class="keyword">go</span>-<span class="built_in">get</span>=<span class="number">1</span></span><br><span class="line">gopkg.in/inconshreveable/<span class="keyword">go</span>-<span class="keyword">update</span>.v0 (download)</span><br><span class="line">github.<span class="keyword">com</span>/kardianos/osext (download)</span><br><span class="line">github.<span class="keyword">com</span>/kr/binarydist (download)</span><br><span class="line">Fetching http<span class="variable">s:</span>//gopkg.in/inconshreveable/<span class="keyword">go</span>-<span class="keyword">update</span>.v0/check?<span class="keyword">go</span>-<span class="built_in">get</span>=<span class="number">1</span></span><br><span class="line">Parsing meta <span class="keyword">tags</span> from http<span class="variable">s:</span>//gopkg.in/inconshreveable/<span class="keyword">go</span>-<span class="keyword">update</span>.v0/check?<span class="keyword">go</span>-<span class="built_in">get</span>=<span class="number">1</span> (status code <span class="number">200</span>)</span><br><span class="line"><span class="built_in">get</span> <span class="string">"gopkg.in/inconshreveable/go-update.v0/check"</span>: found meta <span class="keyword">tag</span> main.metaImport&#123;Prefix:<span class="string">"gopkg.in/inconshreveable/go-update.v0"</span>, VCS:<span class="string">"git"</span>, RepoRoo<span class="variable">t:</span><span class="string">"https://gopkg.in/inconshreveable/go-update.v0"</span>&#125; at http<span class="variable">s:</span>//gopkg.in/inconshreveable/<span class="keyword">go</span>-<span class="keyword">update</span>.v0/check?<span class="keyword">go</span>-<span class="built_in">get</span>=<span class="number">1</span></span><br><span class="line"><span class="built_in">get</span> <span class="string">"gopkg.in/inconshreveable/go-update.v0/check"</span>: verifying non-authoritative meta <span class="keyword">tag</span></span><br><span class="line">Fetching http<span class="variable">s:</span>//gopkg.in/inconshreveable/<span class="keyword">go</span>-<span class="keyword">update</span>.v0?<span class="keyword">go</span>-<span class="built_in">get</span>=<span class="number">1</span></span><br><span class="line">Parsing meta <span class="keyword">tags</span> from http<span class="variable">s:</span>//gopkg.in/inconshreveable/<span class="keyword">go</span>-<span class="keyword">update</span>.v0?<span class="keyword">go</span>-<span class="built_in">get</span>=<span class="number">1</span> (status code <span class="number">200</span>)</span><br><span class="line">Fetching http<span class="variable">s:</span>//gopkg.in/yaml.v1?<span class="keyword">go</span>-<span class="built_in">get</span>=<span class="number">1</span></span><br><span class="line">Parsing meta <span class="keyword">tags</span> from http<span class="variable">s:</span>//gopkg.in/yaml.v1?<span class="keyword">go</span>-<span class="built_in">get</span>=<span class="number">1</span> (status code <span class="number">200</span>)</span><br><span class="line"><span class="built_in">get</span> <span class="string">"gopkg.in/yaml.v1"</span>: found meta <span class="keyword">tag</span> main.metaImport&#123;Prefix:<span class="string">"gopkg.in/yaml.v1"</span>, VCS:<span class="string">"git"</span>, RepoRoo<span class="variable">t:</span><span class="string">"https://gopkg.in/yaml.v1"</span>&#125; at http<span class="variable">s:</span>//gopkg.in/yaml.v1?<span class="keyword">go</span>-<span class="built_in">get</span>=<span class="number">1</span></span><br><span class="line">gopkg.in/yaml.v1 (download)</span><br><span class="line">github.<span class="keyword">com</span>/inconshreveable/<span class="keyword">go</span>-vhost (download)</span><br><span class="line">github.<span class="keyword">com</span>/alecthomas/log4go (download)</span><br><span class="line">github.<span class="keyword">com</span>/nsf/termbox-<span class="keyword">go</span> (download)</span><br><span class="line">github.<span class="keyword">com</span>/mattn/<span class="keyword">go</span>-runewidth (download)</span><br><span class="line">github.<span class="keyword">com</span>/gorilla/websocket (download)</span><br><span class="line"><span class="keyword">go</span> install -<span class="keyword">tags</span> <span class="string">'release'</span> ngrok/main/ngrokd</span><br></pre></td></tr></table></figure><p>出现以上表示编译成功。</p><h5 id="运行服务端ngrok"><a href="#运行服务端ngrok" class="headerlink" title="运行服务端ngrok"></a>运行服务端ngrok</h5><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">./bin/ngrokd -domain=<span class="string">"tunnel.mydomain.com"</span> -httpAddr=<span class="string">":8080"</span> -httpsAddr=<span class="string">":4000"</span></span><br><span class="line">默认的https端口和http端口是<span class="number">443</span>和<span class="number">80</span>，但是这两个端口已经被Nginx占了，所以换成<span class="number">9000</span>和<span class="number">4000</span></span><br></pre></td></tr></table></figure><p>出现以下内容，即为成功</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-attr">[21:30:55 CST 2017/03/09]</span> <span class="selector-attr">[INFO]</span> (ngrok/log.(*PrefixLogger).<span class="attribute">Info</span>:<span class="number">83</span>) <span class="selector-attr">[registry]</span> <span class="selector-attr">[tun]</span> <span class="selector-tag">No</span> <span class="selector-tag">affinity</span> <span class="selector-tag">cache</span> <span class="selector-tag">specified</span></span><br><span class="line"><span class="selector-attr">[21:30:55 CST 2017/03/09]</span> <span class="selector-attr">[INFO]</span> (ngrok/log.<span class="attribute">Info</span>:<span class="number">112</span>) <span class="selector-tag">Listening</span> <span class="selector-tag">for</span> <span class="selector-tag">public</span> <span class="selector-tag">http</span> <span class="selector-tag">connections</span> <span class="selector-tag">on</span> <span class="selector-attr">[::]</span><span class="selector-pseudo">:9000</span></span><br><span class="line"><span class="selector-attr">[21:30:55 CST 2017/03/09]</span> <span class="selector-attr">[INFO]</span> (ngrok/log.<span class="attribute">Info</span>:<span class="number">112</span>) <span class="selector-tag">Listening</span> <span class="selector-tag">for</span> <span class="selector-tag">public</span> <span class="selector-tag">https</span> <span class="selector-tag">connections</span> <span class="selector-tag">on</span> <span class="selector-attr">[::]</span><span class="selector-pseudo">:4000</span></span><br><span class="line"><span class="selector-attr">[21:30:55 CST 2017/03/09]</span> <span class="selector-attr">[INFO]</span> (ngrok/log.<span class="attribute">Info</span>:<span class="number">112</span>) <span class="selector-tag">Listening</span> <span class="selector-tag">for</span> <span class="selector-tag">control</span> <span class="selector-tag">and</span> <span class="selector-tag">proxy</span> <span class="selector-tag">connections</span> <span class="selector-tag">on</span> <span class="selector-attr">[::]</span><span class="selector-pseudo">:4443</span></span><br></pre></td></tr></table></figure><p>可以使用<code>nohup</code>后台运行。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nohup ./bin/ngrokd <span class="attribute">-domain</span>=<span class="string">"tunnel.mydomain.com"</span> <span class="attribute">-httpAddr</span>=<span class="string">":8080"</span> <span class="attribute">-httpsAddr</span>=<span class="string">":4000"</span> &amp;</span><br></pre></td></tr></table></figure><h5 id="编译客户端"><a href="#编译客户端" class="headerlink" title="编译客户端"></a>编译客户端</h5><h6 id="Mac"><a href="#Mac" class="headerlink" title="Mac"></a>Mac</h6><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">GOOS</span>=darwin <span class="attribute">GOARCH</span>=amd64 make release-client</span><br></pre></td></tr></table></figure><h6 id="Windows"><a href="#Windows" class="headerlink" title="Windows"></a>Windows</h6><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">GOOS</span>=windows <span class="attribute">GOARCH</span>=amd64 make release-client</span><br><span class="line"><span class="comment">#以上GOARCH=amd64指的是编译为64位版本，如需32位改成GOARCH=386即可</span></span><br></pre></td></tr></table></figure><p>以上编译成功后可以在./bin目录下找到对应的可执行程序，下载即可。</p></div><p class="readmore"><a href="/posts/62687.html">Leer más</a></p></div><nav class="page-navigator"><a class="extend prev" rel="prev" href="/page/2/">Anterior</a><a class="page-number" href="/">1</a><a class="page-number" href="/page/2/">2</a><span class="page-number current">3</span><a class="page-number" href="/page/4/">4</a><a class="page-number" href="/page/5/">5</a><a class="extend next" rel="next" href="/page/4/">Siguiente</a></nav></div></div><div class="pure-u-1-4 hidden_mid_and_down"><div id="sidebar"><div class="widget"><form class="search-form" action="//www.google.com/search" method="get" accept-charset="utf-8" target="_blank"><input type="text" name="q" maxlength="20" placeholder="Search"><input type="hidden" name="sitesearch" value="https://www.dev-heaven.com"></form></div><div class="widget"><div class="widget-title"><i class="fa fa-folder-o">Categorías</i></div><ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/博客/">博客</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/生活/">生活</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/随笔/">随笔</a></li></ul></div><div class="widget"><div class="widget-title"><i class="fa fa-star-o">Etiquetas</i></div><div class="tagcloud"><a href="/tags/springMVC/" style="font-size:15px">springMVC</a> <a href="/tags/docker/" style="font-size:15px">docker</a> <a href="/tags/express/" style="font-size:15px">express</a> <a href="/tags/POI/" style="font-size:15px">POI</a> <a href="/tags/Java/" style="font-size:15px">Java</a> <a href="/tags/Linux/" style="font-size:15px">Linux</a> <a href="/tags/firewall/" style="font-size:15px">firewall</a> <a href="/tags/MySQL/" style="font-size:15px">MySQL</a> <a href="/tags/mybatis/" style="font-size:15px">mybatis</a> <a href="/tags/Ngrok/" style="font-size:15px">Ngrok</a> <a href="/tags/微信/" style="font-size:15px">微信</a> <a href="/tags/ECS/" style="font-size:15px">ECS</a> <a href="/tags/RabbitMQ/" style="font-size:15px">RabbitMQ</a> <a href="/tags/Nginx/" style="font-size:15px">Nginx</a> <a href="/tags/域名/" style="font-size:15px">域名</a> <a href="/tags/Nodejs/" style="font-size:15px">Nodejs</a> <a href="/tags/nvm/" style="font-size:15px">nvm</a> <a href="/tags/SpringBoot/" style="font-size:15px">SpringBoot</a> <a href="/tags/log4j2/" style="font-size:15px">log4j2</a> <a href="/tags/Docker/" style="font-size:15px">Docker</a> <a href="/tags/x-www-form-urlencoded/" style="font-size:15px">x-www-form-urlencoded</a> <a href="/tags/form-data/" style="font-size:15px">form-data</a> <a href="/tags/axios/" style="font-size:15px">axios</a> <a href="/tags/css/" style="font-size:15px">css</a> <a href="/tags/git/" style="font-size:15px">git</a> <a href="/tags/life/" style="font-size:15px">life</a> <a href="/tags/health/" style="font-size:15px">health</a> <a href="/tags/npm/" style="font-size:15px">npm</a> <a href="/tags/nodejs/" style="font-size:15px">nodejs</a> <a href="/tags/nrm/" style="font-size:15px">nrm</a> <a href="/tags/redis/" style="font-size:15px">redis</a> <a href="/tags/Spring/" style="font-size:15px">Spring</a> <a href="/tags/spring-data-redis/" style="font-size:15px">spring-data-redis</a> <a href="/tags/pyenv/" style="font-size:15px">pyenv</a> <a href="/tags/Python/" style="font-size:15px">Python</a> <a href="/tags/ReentrantLock/" style="font-size:15px">ReentrantLock</a> <a href="/tags/https/" style="font-size:15px">https</a> <a href="/tags/poet/" style="font-size:15px">poet</a> <a href="/tags/shell/" style="font-size:15px">shell</a></div></div><div class="widget"><div class="widget-title"><i class="fa fa-file-o">Recientes</i></div><ul class="post-list"><li class="post-list-item"><a class="post-list-link" href="/posts/48761.html">关于ReentrantLock实现的一点思考</a></li><li class="post-list-item"><a class="post-list-link" href="/posts/61735.html">Java内存优化之POI Excel（三）</a></li><li class="post-list-item"><a class="post-list-link" href="/posts/64862.html">Java内存优化之POI Excel（二）</a></li><li class="post-list-item"><a class="post-list-link" href="/posts/27940.html">Java内存优化之POI Excel（一）</a></li><li class="post-list-item"><a class="post-list-link" href="/posts/955.html">最佳实践之Java基础</a></li><li class="post-list-item"><a class="post-list-link" href="/posts/49259.html">Vue + SpringBoot 小问题记录</a></li><li class="post-list-item"><a class="post-list-link" href="/posts/43546.html">git 删除远程分支</a></li><li class="post-list-item"><a class="post-list-link" href="/posts/37317.html">Java规范笔记---读《阿里巴巴Java开发手册》</a></li><li class="post-list-item"><a class="post-list-link" href="/posts/56838.html">Java获取泛型的真实类型</a></li><li class="post-list-item"><a class="post-list-link" href="/posts/6407.html">RabbitMQ从入门到精通—publish confirm机制</a></li></ul></div><div class="widget"><div class="widget-title"><i class="fa fa-external-link">Blogroll</i></div><ul></ul><a href="http://www.example1.com/" title="site-name1" target="_blank">site-name1</a><ul></ul><a href="http://www.example2.com/" title="site-name2" target="_blank">site-name2</a><ul></ul><a href="http://www.example3.com/" title="site-name3" target="_blank">site-name3</a></div></div></div><div class="pure-u-1 pure-u-md-3-4"><div id="footer">Copyright © 2019 <a href="/." rel="nofollow">菜鸟IT路.</a> Powered by<a rel="nofollow" target="_blank" href="https://hexo.io"> Hexo.</a><a rel="nofollow" target="_blank" href="https://github.com/tufu9441/maupassant-hexo"> Theme</a> by<a rel="nofollow" target="_blank" href="https://github.com/pagecho"> Cho.</a></div></div></div><a class="show" id="rocket" href="#top"></a><script type="text/javascript" src="/js/totop.js?v=0.0.0" async></script><script type="text/javascript" src="//lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js" async></script><script type="text/javascript" src="/js/fancybox.js?v=0.0.0" async></script><link rel="stylesheet" type="text/css" href="//lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css"><script type="text/javascript" src="/js/codeblock-resizer.js?v=0.0.0"></script><script type="text/javascript" src="/js/smartresize.js?v=0.0.0"></script></div></body></html>